<!--
 * @Author: Baishui
 * @Date: 2021-09-28 20:38:11
 * @LastEditors: Baishui
 * @LastEditTime: 2021-10-03 17:36:40
 * @Description: file content
-->
<template>
  <svg width="1000" height="500" id="basic-tree" />
</template>

<script lang="ts">
  import { defineComponent, reactive, toRefs, onMounted } from 'vue'
  import * as d3 from 'd3'
  import { reqChartBasicTree } from '@/api/chart'
  import { isEmpty } from 'lodash-es'

  export default defineComponent({
    name: 'BasicTree',
    components: {},
    setup() {
      const state = reactive({
        g: null as any,
      })

      onMounted(async () => {
        const res = await reqChartBasicTree()
        initSvg()
        render(res)
      })
      let innerWidth = 0
      let innerHeight = 0

      function initSvg() {
        const svg = d3.select('#basic-tree')
        const width = +svg.attr('width')
        const height = +svg.attr('height')
        const margin = { top: 20, left: 40, bottom: 20, right: 50 }
        innerWidth = width - margin.left - margin.right
        innerHeight = height - margin.top - margin.bottom

        state.g = svg.append('g').attr('transform', `translate(${margin.left}, ${margin.top})`)
      }

      function render(data: any) {
        if (isEmpty(data)) return

        let _data = d3.hierarchy(data)

        let root = d3.tree().size([innerHeight, innerWidth])(_data)

        let colors = d3
          .scaleOrdinal()
          .domain(
            root
              .descendants()
              .filter((d: any) => d.depth <= 1)
              .map((d: any) => d.data.name)
          )
          .range(d3.schemeCategory10)

        const fill = (d: any) => {
          if (d.depth === 0) return colors(d.data.name)
          while (d.depth > 1) d = d.parent

          return colors(d.data.name)
        }

        const { g }: any = state

        // 线
        g.append('g')
          .attr('class', 'path-group')
          .selectAll('pth')
          .data(root.links())
          .join('path')
          .attr('fill', 'none')
          .attr('stroke', 'black')
          .attr('stroke-width', 1.5)
          .attr(
            'd',
            d3
              .linkHorizontal() // 贝塞尔曲线 水平切线
              // linkHorizontal() // 垂直切线
              .x((d: any) => d.y) // 左右排列
              .y((d: any) => d.x)
          )

        // 点
        g.append('g')
          .attr('class', 'circle-group')
          .selectAll('circle')
          .data(root.descendants())
          .join('circle')
          .attr('stroke-width', 3)
          .attr('fill', fill)
          .attr('cx', (d: any) => d.y)
          .attr('cy', (d: any) => d.x)
          .attr('r', 6)

        // 名称
        g.append('g')
          .attr('class', 'name-group')
          .selectAll('text')

          .data(root.descendants())
          .join('text')
          .attr('text-anchor', (d: any) => (d.children ? 'end' : 'start'))
          .attr('x', (d: any) => (d.children ? -6 : 6) + d.y)
          .attr('y', (d: any) => d.x + 5)
          .text((d: any) => d.data.name)
      }

      return {
        ...toRefs(state),
      }
    },
  })
</script>
<style lang="less" scoped>
  .wrapper {
  }
</style>
